package ace.tool.generate.code.impl.resolver.ui.resolver;

import ace.tool.generate.code.impl.manager.common.EntityModelManager;
import ace.tool.generate.code.impl.resolver.ui.model.bo.*;
import ace.tool.generate.code.impl.service.model.input.GenerateInput;
import ace.tool.generate.code.impl.service.model.input.GenerateModelFieldInput;
import ace.tool.generate.code.impl.service.model.input.GenerateModelInput;
import java.util.List;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;

/**
 * @author caspar
 * @date 2023/11/17 10:34
 */
@RequiredArgsConstructor
public class UiProjectInfoResolver {
  private final GenerateInput input;
  private final EntityModelManager entityModelManager = EntityModelManager.getInstance();

  public UiProjectInfo resolve() {
    UiProjectCommonInfo uiProjectCommonInfo = new UiProjectCommonInfoResolver(this.input).resolve();
    UiApiConfigClassInfo uiApiConfigClassInfo = this.getUiApiConfigClassInfo(uiProjectCommonInfo);
    List<ResponseClassInfo> responses = this.getCoreTypeResponses(uiProjectCommonInfo);
    List<UiViewListClassInfo> uiViewListClassInfos =
        this.getUiViewListClassInfos(uiProjectCommonInfo);
    List<UiEnumClassInfo> enumClassInfos = this.getEnumClassInfos(uiProjectCommonInfo);
    List<UiMockServerApiClassInfo> mockServerApiClassInfos =
        this.getMockServerApiClassInfos(uiProjectCommonInfo, responses, uiApiConfigClassInfo);
    List<UiServerApiClassInfo> uiServerApiClassInfos =
        this.getUiServerApiClassInfos(uiProjectCommonInfo, uiApiConfigClassInfo, responses);
    List<UiServiceClassInfo> uiServiceClassInfos =
        this.getUiServiceClassInfos(uiProjectCommonInfo, uiServerApiClassInfos, responses);
    UiMockServerApiIndexClassInfo uiMockServerApiIndexClassInfo =
        this.getUiMockServerApiIndexClassInfo(uiProjectCommonInfo, mockServerApiClassInfos);
    return UiProjectInfo.builder()
        .info(uiProjectCommonInfo)
        .frameworkDirs(this.getFrameworkDirs(uiProjectCommonInfo))
        .responses(responses)
        .enumClassInfos(enumClassInfos)
        .mockServerApiClassInfos(mockServerApiClassInfos)
        .uiViewListClassInfos(uiViewListClassInfos)
        .apiConfigClassInfo(uiApiConfigClassInfo)
        .uiServerApiClassInfos(uiServerApiClassInfos)
        .uiServiceClassInfos(uiServiceClassInfos)
        .uiMockServerApiIndexClassInfo(uiMockServerApiIndexClassInfo)
        .build();
  }

  private UiMockServerApiIndexClassInfo getUiMockServerApiIndexClassInfo(
      UiProjectCommonInfo uiProjectCommonInfo,
      List<UiMockServerApiClassInfo> mockServerApiClassInfos) {
    return new UiMockServerApiIndexClassInfoResolver(
            input, uiProjectCommonInfo, mockServerApiClassInfos)
        .resolve();
  }

  private List<String> getFrameworkDirs(UiProjectCommonInfo uiProjectCommonInfo) {
    return this.input.getUiFrameworkDirs().stream()
        .map(
            relativeDir -> {
              return uiProjectCommonInfo.getCoreDir()
                  + "/"
                  + uiProjectCommonInfo.getProjectModuleCodeName()
                  + relativeDir;
            })
        .collect(Collectors.toList());
  }

  private List<UiServiceClassInfo> getUiServiceClassInfos(
      UiProjectCommonInfo uiProjectCommonInfo,
      List<UiServerApiClassInfo> uiServerApiClassInfos,
      List<ResponseClassInfo> responses) {
    return this.input.getModels().stream()
        .map(
            modelInput -> {
              String entityModelId = entityModelManager.getEntityModelId(input, modelInput);
              ResponseClassInfo responseClassInfo =
                  entityModelManager.getUiResponseClassInfoByEntityId(responses, entityModelId);
              UiServerApiClassInfo uiServerApiClassInfo =
                  entityModelManager.getUiServerApiClassInfoByEntityId(
                      uiServerApiClassInfos, entityModelId);
              UiServiceClassInfo uiServiceClassInfo =
                  this.getUiServiceClassInfo(
                      uiProjectCommonInfo, uiServerApiClassInfo, modelInput, responseClassInfo);
              return uiServiceClassInfo;
            })
        .collect(Collectors.toList());
  }

  private UiServiceClassInfo getUiServiceClassInfo(
      UiProjectCommonInfo uiProjectCommonInfo,
      UiServerApiClassInfo uiServerApiClassInfo,
      GenerateModelInput modelInput,
      ResponseClassInfo responseClassInfo) {
    return new UiServiceClassInfoResolver(
            this.input, modelInput, uiServerApiClassInfo, responseClassInfo, uiProjectCommonInfo)
        .resolve();
  }

  private List<UiServerApiClassInfo> getUiServerApiClassInfos(
      UiProjectCommonInfo uiProjectCommonInfo,
      UiApiConfigClassInfo uiApiConfigClassInfo,
      List<ResponseClassInfo> responses) {
    return this.input.getModels().stream()
        .map(
            modelInput -> {
              String entityModelId = entityModelManager.getEntityModelId(input, modelInput);
              ResponseClassInfo responseClassInfo =
                  entityModelManager.getUiResponseClassInfoByEntityId(responses, entityModelId);
              UiServerApiClassInfo uiServerApiClassInfo =
                  this.getUiServerApiClassInfo(
                      uiProjectCommonInfo, uiApiConfigClassInfo, modelInput, responseClassInfo);
              return uiServerApiClassInfo;
            })
        .collect(Collectors.toList());
  }

  private UiServerApiClassInfo getUiServerApiClassInfo(
      UiProjectCommonInfo uiProjectCommonInfo,
      UiApiConfigClassInfo uiApiConfigClassInfo,
      GenerateModelInput modelInput,
      ResponseClassInfo responseClassInfo) {
    return new UiServerApiClassInfoResolver(
            this.input, modelInput, uiApiConfigClassInfo, responseClassInfo, uiProjectCommonInfo)
        .resolve();
  }

  private UiApiConfigClassInfo getUiApiConfigClassInfo(UiProjectCommonInfo uiProjectCommonInfo) {
    return UiApiConfigClassInfoResolver.builder()
        .uiProjectCommonInfo(uiProjectCommonInfo)
        .input(input)
        .build()
        .resolve();
  }

  private List<UiViewListClassInfo> getUiViewListClassInfos(
      UiProjectCommonInfo uiProjectCommonInfo) {
    return this.input.getModels().stream()
        .map(modelInput -> this.getUiViewListClassInfo(uiProjectCommonInfo, modelInput))
        .collect(Collectors.toList());
  }

  private UiViewListClassInfo getUiViewListClassInfo(
      UiProjectCommonInfo uiProjectCommonInfo, GenerateModelInput modelInput) {
    return new UiViewListClassResolver(this.input, modelInput, uiProjectCommonInfo).resolve();
  }

  private List<UiMockServerApiClassInfo> getMockServerApiClassInfos(
      UiProjectCommonInfo uiProjectCommonInfo,
      List<ResponseClassInfo> responseClassInfos,
      UiApiConfigClassInfo uiApiConfigClassInfo) {
    return input.getModels().stream()
        .map(
            modelInput ->
                this.getMockServerApiClassInfo(
                    modelInput, uiProjectCommonInfo, responseClassInfos, uiApiConfigClassInfo))
        .collect(Collectors.toList());
  }

  private UiMockServerApiClassInfo getMockServerApiClassInfo(
      GenerateModelInput modelInput,
      UiProjectCommonInfo uiProjectCommonInfo,
      List<ResponseClassInfo> responseClassInfos,
      UiApiConfigClassInfo uiApiConfigClassInfo) {
    String entityModelId = entityModelManager.getEntityModelId(input, modelInput);
    ResponseClassInfo responseClassInfo =
        entityModelManager.getUiResponseClassInfoByEntityId(responseClassInfos, entityModelId);
    return new UiMockServerApiClassInfoResolver(
            input, modelInput, uiProjectCommonInfo, responseClassInfo, uiApiConfigClassInfo)
        .resolve();
  }

  private List<UiEnumClassInfo> getEnumClassInfos(UiProjectCommonInfo uiProjectCommonInfo) {
    return input.getModels().stream()
        .map(
            modelInput ->
                modelInput.getFields().stream()
                    .filter(modelFieldInput -> modelFieldInput.getEnums() != null)
                    .map(
                        modelFieldInput ->
                            this.getEnumClassInfo(modelInput, modelFieldInput, uiProjectCommonInfo))
                    .collect(Collectors.toList()))
        .flatMap(List::stream)
        .collect(Collectors.toList());
  }

  private UiEnumClassInfo getEnumClassInfo(
      GenerateModelInput modelInput,
      GenerateModelFieldInput modelFieldInput,
      UiProjectCommonInfo uiProjectCommonInfo) {

    return UiEnumClassInfoResolver.builder()
        .modelFieldInput(modelFieldInput)
        .modelInput(modelInput)
        .input(input)
        .uiProjectCommonInfo(uiProjectCommonInfo)
        .build()
        .resolve();
  }

  private List<ResponseClassInfo> getCoreTypeResponses(UiProjectCommonInfo uiProjectCommonInfo) {
    return this.input.getModels().stream()
        .map(modelInput -> this.getCoreTypeResponse(uiProjectCommonInfo, modelInput))
        .collect(Collectors.toList());
  }

  private ResponseClassInfo getCoreTypeResponse(
      UiProjectCommonInfo uiProjectCommonInfo, GenerateModelInput modelInput) {
    return new ResponseClassInfoResolver(this.input, modelInput, uiProjectCommonInfo).resolve();
  }
}
